#if 0
/****************************************************************************

	COPYRIGHT(C) MAXSI SOFTWARE, JONAS 'SORTIE' TERMANSEN 2008, 2009

    This file is part of Maxsi Distribution.

    Maxsi Distribution is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Maxsi Distribution is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Maxsi Distribution.  If not, see <http://www.gnu.org/licenses/>.

	*/ #include "MaxsiDistributionContributors.h" /*

	If you modify this file, please enter your name below and provide contact
	information in MaxsiDistributionContributors.h. For more information please see
	MaxsiEngineContributors.h.
	
	Contributors to this file:

	- Jonas 'Sortie' Termansen
	- [your name here]

	MaxsiDistribution.dll
	Distributing since 2008

	MaxsiUpdate.cpp
	Functions that ensure this product is up to date.

****************************************************************************/

	#include "MaxsiEngine.h"
	#include "MaxsiDistributionLink.h"
	#include <io.h>
	#include <direct.h>
	#include <iostream> 
	#include <fcntl.h>
	#include <SYS\Stat.h>
	#include <process.h> 
	#include "Data.h"
	//#include "MaxsiUpdate.h"

	// Local variables
	bool			HasUpdates						=	false;
	bool			NeedsUpdatingUpdates			=	false;
	bool			AbnormalTerminationRequired		=	false;

	UpdateProductArguments		g_Arg;

	// Redeclare an inferface used to override the installer
	//DECLARE_EXTERN_FUNCTION(bool, ErrorFunc,		(const char* Error))	;//=	(type_ErrorFunc)		&Error;
	//DECLARE_EXTERN_FUNCTION(bool, InfoFunc,			(const char* Error))	;//=	(type_InfoFunc)			&Info;
	//DECLARE_EXTERN_FUNCTION(bool, StatusFunc,		(const char* Status))	;//=	(type_StatusFunc)		&SetStatus;
	//DECLARE_EXTERN_FUNCTION(bool, SubStatusFunc,	(const char* Status))	;//=	(type_SubStatusFunc)	&SetSubStatus;
	//DECLARE_EXTERN_FUNCTION(bool, ProgressFunc,		(int Progress))			;//=	(type_ProgressFunc)		&SetProgress;
	//DECLARE_EXTERN_FUNCTION(bool, DownloadFunc,		())						;//=	0;
	//DECLARE_EXTERN_FUNCTION(bool, InstallFunc,		())						;//=	0;
	//DECLARE_EXTERN_FUNCTION(bool, NoInternet,		())						;//=	0;
	//DECLARE_EXTERN_FUNCTION(bool, NeedsUpdating,	())						;//=	0;

	DECLARE_FUNCTION_HEADER(bool,PingBackEngine,(char*));
	DECLARE_FUNCTION_SOURCE(bool,PingBackEngine,(char*));

	// Handle the dll functions and stuff

	BOOL APIENTRY DllMain(HANDLE hModule, 
						  DWORD  ul_reason_for_call, 
						  LPVOID lpReserved)
	{
		switch( ul_reason_for_call )
		{
			case DLL_PROCESS_ATTACH:
			break;
			case DLL_THREAD_ATTACH:
			break;
			case DLL_THREAD_DETACH:
			break;
			case DLL_PROCESS_DETACH:
			break;
		}
		return true;
	}

	// Error reporting function

	bool	ReportError(const char* Error, bool DontShowNotepad)
	{
		int fh = 0;

		char*	WorkingDir	=	GetWorkingDirectory();
		char*	FileName	=	BuildString(2,WorkingDir,"MaxsiDistributionError.txt");

		_sopen_s(&fh,File, _O_CREAT | O_TRUNC | O_BINARY | O_WRONLY, _SH_DENYNO, _S_IREAD | _S_IWRITE);

		if (fh == -1)
		{
			delete[] WorkingDir;
			delete[] File;
			return false;
		}
		else
		{
			char* Header = "An occured occured inside MaxsiDistribution.dll\r\n\r\n";
			_write(fh,Header,strlen(Header));
			_write(fh,Error,strlen(Error));
			_close(fh);		
		}
		
		size_t ReadMeCommandSize = strlen("notepad \"") + strlen(File) + 1;
		char* ReadMeCommand = new char[ReadMeCommandSize];
		ReadMeCommand[0] = 0;
		
		strcat_s(ReadMeCommand,ReadMeCommandSize,"notepad \"");
		strcat_s(ReadMeCommand,ReadMeCommandSize,File);

		char*	ReadMeCommand	=	BuildString(2,"notepad \"",File);

		if (!DontShowNotepad)
		{
			WinExec(ReadMeCommand,SW_SHOW);
		}
		delete[] ReadMeCommand;
		delete[] WorkingDir;
		delete[] File;

		// If we do this, we must close the product
		AbnormalTerminationRequired = true;
		
		return true;
	}

	// Declare overriding functions

	bool Update_Error(const char* Error)
	{
		return true;
	}

	bool Update_Info(const char* Error)
	{
		return true;
	}

	bool Update_NewsUpdated(const char* News)
	{
		return true;
	}

	bool Update_SetStatus(const char* Status)
	{
		return true;
	}

	bool Update_SetSubStatus(const char* Status)
	{
		return true;
	}

	bool Update_SetProgress(int Progress)
	{
		return true;
	}

	bool Update_DoDownload()
	{
		HasUpdates = true;
		return false;
	}

	bool Update_DoInstall()
	{
		return false;
	}

	bool Update_NoInternet()
	{
		return false;
	}

	bool Update_NeedsUpdating()
	{
		if (!Download("MaxsiDistributionUpdate.dll",g_Arg.FolderName))
		{
			AbnormalTerminationRequired = true;
			ReportError("Couldn't download the software required to update the updating software. Please reinstall this product. " SupportId(39));

			return false;
		}
		NeedsUpdatingUpdates = true;
		return true;
	}


	// Install function
	DWORD WINAPI Install(LPVOID parameter);

	// Returns true if an update is available
	bool	UpdateAvailable( char* FolderName, char* WorkingDir, char* Username )
	{
		HasUpdates		=	false;
		IsIngame		=	true;

		// Setup the interface
		ErrorFunc		=	(type_ErrorFunc)		&ReportError;
		InfoFunc		=	(type_InfoFunc)			&Update_Info;
		NewsUpdatedFunc	=	(type_NewsUpdatedFunc)	&Update_NewsUpdated;
		StatusFunc		=	(type_StatusFunc)		&Update_SetStatus;
		SubStatusFunc	=	(type_SubStatusFunc)	&Update_SetSubStatus;
		ProgressFunc	=	(type_ProgressFunc)		&Update_SetProgress;
		CheckBlockStates=	(type_CheckBlockStates)	&CheckBlockStatesFast;
		DownloadFunc	=	(type_DownloadFunc)		&Update_DoDownload;
		InstallFunc		=	(type_InstallFunc)		&Update_DoInstall;
		NoInternet		=	(type_NoInternet)		&Update_NoInternet;
		NeedsUpdating	=	(type_NeedsUpdating)	&Update_NeedsUpdating;

		SteamUserName	=	Username;
		InstallPath		=	BuildString(1,FolderName);
		Password		=	0;

		unsigned int	NumSlashes = 0;

		for (size_t N = strlen(InstallPath)-2; N > 0; N--)
		{
			if (InstallPath[N] == '/' ||
				InstallPath[N] == '\\' )
			{
				NumSlashes++;

				if ( NumSlashes == 3 )
				{
					InstallPath[N]=0;
					break;
				}
			}
		}

		InstallProduct();

		return HasUpdates;
	}

	bool	InstallUpdate(char* FolderName, char* Username)
	{
		char*	UpdateCommand	=	BuildString(4,"\"",MDDir,"/bin/MaxsiInstaller.exe\"",Username);
		
		//WinExec(UpdateCommand,SW_SHOW);

		RunProcess(UpdateCommand,(HWND)-1);

		delete[] UpdateCommand;

		return true;
	}


	// Returns true if the product can be run, false if an update-process has begun.
	LINK	int	UpdateProduct( UpdateProductArguments Arg )
	{
		if (sizeof(Arg) != Arg.Size) { return RESULT_INVALID_PARAMETER_SIZE; }
		g_Arg = Arg;

		// Calculate the SourceMods Directory
		// Convert from [Steam]/SteamApps/SourceMods/Altered Transmission/
		// to			[Steam]/

		char*	SteamFolder		=	BuildString(1,Arg.FolderName);
		size_t	SteamFolderLen	=	strlen(SteamFolder);
		size_t	NumSlashes		=	0;

		for (size_t N = SteamFolderLen; N > 0; N--)
		{
			if (Arg.WorkingDir[N] == '/'||Arg.WorkingDir[N] == '\\')
			{
				NumSlashes++;
				if ( NumSlashes == 4)
				{
					SteamFolder[N+1]	=	0;
					break;
				}
			}
		}

		int fh = 0;							
		_sopen_s(&fh,"MaxsiDistribution.mis", _O_CREAT | O_TRUNC | O_BINARY | O_WRONLY, _SH_DENYNO, _S_IREAD | _S_IWRITE);

		if (fh == -1)
		{
		}
		else
		{
			/*
			Product "Altered Transmission - Demo 8"
			ProductVersion "Demo 8"
			DownloadName "Altered Transmission - Demo 8"
			DownloadVersion "AT8"
			Username "sortie"
			UpdateProduct ""
			InstallPath "G:\programmer\valve\steam\"
			OnCompleted "http://www.maxsi.dk"
			*/
			
			char* OnComplete = BuildString(5,
				"%",
				Arg.GameFolder,
				"hl2.exe% -game %",
				Arg.FolderName,
				"%");

			char* Out = BuildString(15,
				"Application/x-MaxsiEngineInstallerScript/2.0\r\n"
				"Application: x-MaxsiEngineInstaller\r\n\r\n"
				"MIS_ProductName \"",Arg.Product,"\"\r\n"
				"MIS_ProductVersion \"",Arg.ProductVersion,"\"\r\n"
				"MIS_DownloadName \"",Arg.DownloadName,"\"\r\n"
				"MIS_DownloadVersion \"",Arg.DownloadVersion,"\"\r\n"
				"MIS_Username \"",Arg.Username,"\"\r\n"
				"MIS_InstallPath \"",SteamFolder,"\"\r\n"
				"MIS_UpdateProduct \"\"\r\n"
				"MIS_OnCompleted \"",OnComplete,
				"\"\r\n" // TODO: FIND THE ARGUMENTS REQUIRE TO RUN THE MOD AGAIN!
				);

			_write(fh,Out,strlen(Out));
			_close(fh);

			delete[] Out;
			delete[] OnComplete;
		}

		ProductName			=	Arg.Product;
		ProductVersion		=	Arg.ProductVersion;
		DownloadName		=	Arg.DownloadName;
		DownloadVersion		=	Arg.DownloadVersion;

		// Check for updates
		if (UpdateAvailable(Arg.FolderName,Arg.WorkingDir,Arg.Username))
		{ 
			// Update
			if ( InstallUpdate(Arg.FolderName,Arg.Username) )
			{
				// Close the product as soon as possible.
				PostQuitMessage(0);

				delete[] SteamFolder;
				return RESULT_DONT_RUN;
			}
		}

		delete[] SteamFolder;
		
		if (AbnormalTerminationRequired)
		{
			return RESULT_DONT_RUN;
		}

		if ( NeedsUpdatingUpdates )
		{
			return RESULT_UPDATE_UPDATING_SOFTWARE;
		}

		return RESULT_RUN;
	}

#define PingBackToEngine(parameter) if ( PingBackFunc ) { PingBackFunc(parameter); }

	LINK	bool	PingBack		( char* Function, char* Parameter, char* Username, char* Product, char* Version, type_PingBackEngine PingBackFunc)
	{
#if 0
		char** Parameters = (char**)LPParameters;

		// Reget!
		char* Function	=	Parameters[0];
		char* Parameter	=	Parameters[1];
		char* Username	=	Parameters[2];
		char* Product	=	Parameters[3];
		char* Version	=	Parameters[4];
#endif

		HTTPParser_Struct Reply;

		char*		DownloadURI		=	BuildString(10,"/distribution/?action=pingback&product=",Product,"&version=",Version,"&username=",Username,"&function=",Function,"&parameter=",Parameter);
		str_replace(DownloadURI			," ","+");
		char*		Request			=	BuildString(3,"GET ",DownloadURI," HTTP/1.1\r\nHost: www.maxsi.dk\r\nConnection: Close\r\n\r\n");
		size_t		ReplySize		=	0;
					Reply			=	ConnectAndSendHTTPQuery(Request,strlen(Request),"www.maxsi.dk");

		if ( !Reply.In )
		{
			PingBackToEngine("Couldn't connect to the Content Server. Please make sure you are connected to the Internet. " SupportId(14));
			return false;
		}
		if ( !Reply.Out )
		{
			PingBackToEngine("ConnectAndSendHTTPQuery did not return a Reply.Out! " SupportId(15));			
			PingBackToEngine(Reply.In);
			return false;
		}
		if (Reply.OutLenght==2&&memcmp(Reply.Out,"OK",2)==0)
		{
			PingBackToEngine("Statistics successfully uploaded to content server as described in end-user agreement.");
		}
		else
		{
			PingBackToEngine("The content server did not return 'OK'! " SupportId(16));
			char* Out = BuildString(3,"'",Reply.Out,"'");
			char LenStr[33];
			_itoa_s((int)Reply.OutLenght,LenStr,33,10);
			PingBackToEngine(Out);
			PingBackToEngine(LenStr);
			delete[] Out;
			return false;
		}

		delete[]	Request;
		delete[]	DownloadURI;
		DeleteHTTPParser_Struct(Reply);
		return true;
	}
#if 0
	LINK	bool	PingBack		( char* Function, char* Parameter, char* Username, char* Product, char* Version )
	{
		char**	Parameters = new char*[5];
		Parameters[0] = Function;
		Parameters[1] = Parameter;
		Parameters[2] = Username;
		Parameters[3] = Product;
		Parameters[4] = Version;		
#if 1

		PingBackThreaded((void*)Parameters);

#elif 0
		
		ReportError("PingBack",true);


		if ( _beginthread(PingBackThreaded,0,(void*)Parameters) == -1L)
		{
			// Find the error
			int out = 0;
			char str[33];
			_get_errno(&out);
			_itoa_s(out,str,33,10);
			ReportError(str);
		}
		else
		{
			//ReportError("Threaded success!");
		}
#else
		try
		{
			HANDLE	PingBackThread = CreateThread(NULL,0,PingBackThreaded,(LPVOID)Parameters,0,NULL);
		}
		catch (...)
		{
			LPTSTR pszMessage;
			DWORD dwLastError = GetLastError(); 

			FormatMessageA(
				FORMAT_MESSAGE_ALLOCATE_BUFFER | 
				FORMAT_MESSAGE_FROM_SYSTEM |
				FORMAT_MESSAGE_IGNORE_INSERTS,
				NULL,
				dwLastError,
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
				(LPTSTR)&pszMessage,
				0, NULL );

			// Display the error message and exit the process

			ReportError(pszMessage);		

			LocalFree(pszMessage);
		}
#endif
		return true;
	}
#endif
#endif